package com.mapfinal.server.service.tile;

import java.awt.image.BufferedImage;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;

import com.jfinal.kit.StrKit;
import com.lambkit.Lambkit;
import com.mapfinal.converter.scene.SphericalMercatorProjection;
import com.mapfinal.geometry.Latlng;
import com.mapfinal.server.MapfinalServerConfig;

public class TileParam {

	private Integer zoom = 0;
	private Integer x;
	private Integer y;
	private String crs = "EPSG:3857";// "EPSG:4326";

	private String serverType = "mapfinal";
	private String server = "default";
	private String layer;
	private String time;
	private String styles;
	private String pathName;
	private String suffix = "png";// 图片后缀

	private boolean tms = false;
	// 是否缓存
	private String cache = "none";
	// 过滤条件
	private String filter;
	
	public TileParam(Integer x, Integer y, Integer zoom) {
		this.zoom = zoom;
		this.x = x;
		this.y = y;
		MapfinalServerConfig config = Lambkit.config(MapfinalServerConfig.class);
		this.server = config.getMapServerName();
		this.serverType = config.getMapServerType();
	}

	public TileParam(Integer x, Integer y, Integer zoom, String crs) {
		this.zoom = zoom;
		this.x = x;
		this.y = y;
		this.crs = crs;
		MapfinalServerConfig config = Lambkit.config(MapfinalServerConfig.class);
		this.server = config.getMapServerName();
		this.serverType = config.getMapServerType();
	}

	/**
	 * 将lnglat地理坐标系转换为tile瓦片坐标系
	 * 
	 * @param latlng
	 * @param zoom
	 */
	public TileParam(Latlng latlng, int zoom) {
		this.zoom = zoom;
		double n = Math.pow(2, zoom);
		double tileX = ((latlng.lng() + 180) / 360) * n;
		double tileY = (1
				- (Math.log(Math.tan(Math.toRadians(latlng.lat())) + (1 / Math.cos(Math.toRadians(latlng.lat()))))
						/ Math.PI))
				/ 2 * n;
		this.x = new Double(tileX).intValue();
		this.y = new Double(tileY).intValue();
		MapfinalServerConfig config = Lambkit.config(MapfinalServerConfig.class);
		this.server = config.getMapServerName();
		this.serverType = config.getMapServerType();
	}

	public boolean isOk() {
		if (StrKit.isBlank(layer) || StrKit.isBlank(server)) {
			return false;
		}
		return true;
	}

	/**
	 * 将tile(瓦片)坐标系转换为lnglat(地理)坐标系
	 * 
	 * @return
	 */
	public Coordinate toLatlng() {
		if ("EPSG:4326".equals(crs)) {
			double n = Math.pow(2, zoom);
			double m = 2 * n;
			double lng = x / m * 360.0 - 180.0;
			double lat = 90.0 - y / n * 180.0;
			return new Coordinate(lng, lat);
		} else {
			double d = SphericalMercatorProjection.MAX_DIMENSION;
			double n = Math.pow(2, zoom);
			double lng = x / n * (2 * d) - d;
			double lat = d - y / n * (2 * d);
			// double lat = Math.atan(Math.sinh(Math.PI * (1 - 2 * y / n)));
			// lat = lat * 180.0 / Math.PI;
			return new Coordinate(lng, lat);
			// SphericalMercatorProjection smp = new SphericalMercatorProjection();
			// return smp.unproject(new ScenePoint(clng, clat));
		}
	}

	public Envelope toEnvelope() {
		Coordinate latlng1 = toLatlng();
		if ("EPSG:4326".equals(crs)) {
			double n = Math.pow(2, zoom);
			double m = 2 * n;
			double lng = latlng1.getX() + 360.0 / m;
			double lat = latlng1.getY() - 180.0 / n;
			Coordinate latlng0 = new Coordinate(lng, lat);
			return new Envelope(latlng0, latlng1);
		} else {
			double d = SphericalMercatorProjection.MAX_DIMENSION;
			double n = Math.pow(2, zoom);
			double lng = (x + 1) / n * (2 * d) - d;
			double lat = d - (y + 1) / n * (2 * d);
			// SphericalMercatorProjection smp = new SphericalMercatorProjection();
			// Latlng latlng0 = smp.unproject(new ScenePoint(clng, clat));
			// double lng = latlng1.lng() + 360.0 / n;
			// double lat = latlng1.lat() - 180.0 / n;
			// double lat0 = Math.atan(Math.sinh(Math.PI * (1 - 2 * (y+1) / n)));
			// lat0 = lat0 * 180.0 / Math.PI;
			// double lat = lat0;//latlng1.lat() - lat0;
			// System.out.println(x + ": " + latlng1.lng() + "," + lng + " & " + y + ": " +
			// latlng1.lat() + "," + lat);
			Coordinate latlng0 = new Coordinate(lng, lat);
			return new Envelope(latlng0, latlng1);
		}
	}

	public BufferedImage getImageFromCache(String key) {
		return Lambkit.getCache().get("MAP_CACHE_TILE", key);
	}

	public void setImageToCache(String key, BufferedImage image) {
		Lambkit.getCache().put("MAP_CACHE_TILE", key, image);
	}

	public BufferedImage getEmptyImage() {
		BufferedImage image = Lambkit.getCache().get("MAP_CACHE_TILE", "EMPTY_IMAGE");
		if (image == null) {
			image = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);
			Lambkit.getCache().put("MAP_CACHE_TILE", "EMPTY_IMAGE", image);
		}
		return image;
	}

	public Integer getZoom() {
		return zoom;
	}

	public void setZoom(int zoom) {
		this.zoom = zoom;
	}
	
	public int getZ() {
		// TODO Auto-generated method stub
		return zoom;
	}

	public Integer getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public Integer getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public String getCrs() {
		return crs;
	}

	public void setCrs(String crs) {
		this.crs = crs;
	}

	public String getServer() {
		return server;
	}

	public void setServer(String server) {
		if (StrKit.isBlank(server))
			return;
		if (server.contains(":")) {
			String[] servers = server.split(":");
			this.serverType = servers[0];
			this.server = servers[1];
		} else {
			this.server = server;
		}
	}

	public String getLayer() {
		return layer;
	}

	public void setLayer(String layer) {
		this.layer = layer;
	}

	public String getTime() {
		return time;
	}

	public void setTime(String time) {
		this.time = time;
	}

	public String getStyles() {
		return styles;
	}

	public void setStyles(String styles) {
		this.styles = styles;
	}

	public String getPathName() {
		return pathName;
	}

	public void setPathName(String pathName) {
		this.pathName = pathName;
	}

	public String getServerType() {
		return serverType;
	}

	public void setServerType(String serverType) {
		this.serverType = serverType;
	}

	public String getSuffix() {
		return suffix;
	}

	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}

	public boolean isTms() {
		return tms;
	}

	public void setTms(boolean tms) {
		this.tms = tms;
	}

	public String getCache() {
		return cache;
	}

	public void setCache(String cache) {
		this.cache = cache;
	}

	public String getFilter() {
		return filter;
	}

	public void setFilter(String filter) {
		this.filter = filter;
	}
}
